package com.xc.sys.service;

import com.google.common.base.Optional;
import com.google.common.cache.CacheBuilder;
import com.google.common.cache.CacheLoader;
import com.google.common.cache.LoadingCache;
import com.xc.common.object.PageInfo;
import com.xc.common.tool.BeanAid;
import com.xc.db.Tables;
import com.xc.db.tables.SysDict;
import com.xc.db.tables.records.SysDictRecord;
import com.xc.sys.entity.SysDictEntity;
import java.util.List;
import java.util.concurrent.ExecutionException;
import org.apache.commons.lang3.StringUtils;
import org.jooq.*;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

@Service
public class SysDictService {
	@Autowired
	private DSLContext dsl;
	private SysDict DICT = SysDict.SYS_DICT.as("DICT");
	public SysDict getTable() {
		return DICT;
	}
	public SysDictEntity gtetDictByCode(String parentCode,String code) {
		List<SysDictEntity> parentDicts = select(DICT.CODE.eq(parentCode),DICT.ORDERNO.asc());
		Integer pid = Integer.valueOf(parentDicts.get(0).getId());
		List<SysDictEntity> kids = select(DICT.PARENT_ID.eq(pid).and(DICT.CODE.eq(code)),DICT.ORDERNO.asc(), DICT.CODE.asc());
		SysDictEntity dict = kids.get(0);
		return dict;
	}
	public List<SysDictEntity> selectByParentId(Integer parentId, SortField<?>... orderby) {
		Result<Record> result = null;
		if (parentId == null) {
			result = dsl.select().from(DICT).where(DICT.PARENT_ID.isNull()).orderBy(orderby).fetch();
		} else {
			result = dsl.select().from(DICT).where(new Condition[] { this.DICT.PARENT_ID.eq(parentId) }).orderBy(orderby).fetch();
		}
		List<SysDictEntity> list = result.into(SysDictEntity.class);
		return list;
	}
	public List<SysDictEntity> selectListByParentCode(String code, SortField<?>... orderby) {
		Result<Record> result = dsl.select().from(DICT).where("parent_id in(select id from sys_dict where code='"+code+"')").orderBy(orderby).fetch();
		List<SysDictEntity> list = result.into(SysDictEntity.class);
		return list;
	}

	public PageInfo<SysDictEntity> selectByParentId(Integer parentId, PageInfo<SysDictEntity> page,SortField<?>... orderby) {
		Long count = countByParentId(parentId);
		page.setCount(count);
		Result<Record> result = null;
		if (parentId == null) {
			result = this.dsl.select(new SelectField[0]).from(this.DICT)
					.where(new Condition[] { this.DICT.PARENT_ID.isNull() }).orderBy(orderby)
					.limit(page.getLimit().intValue()).offset(page.getBeginNum()).fetch();
		} else {
			result = this.dsl.select(new SelectField[0]).from(this.DICT)
					.where(new Condition[] { this.DICT.PARENT_ID.eq(parentId) }).orderBy(orderby)
					.limit(page.getLimit().intValue()).offset(page.getBeginNum()).fetch();
		}
		List<SysDictEntity> list = result.into(SysDictEntity.class);
		page.setResult(result);
		page.setList(list);
		return page;
	}
	public Long count(Condition cond) {
		Long count = dsl.selectCount().from(DICT).where(cond).fetchOneInto(Long.class);
		return count;
	}
	public Long countByParentId(Integer parentId) {
		Long count = null;
		if (parentId == null) {
			count = this.dsl.selectCount().from(this.DICT)
					.where(new Condition[] { this.DICT.PARENT_ID.isNull() }).fetchOneInto(Long.class);
		} else {
			count = this.dsl.selectCount().from(this.DICT)
					.where(new Condition[] { this.DICT.PARENT_ID.eq(parentId) }).fetchOneInto(Long.class);
		}
		return count;
	}
	public Result<Record> select(Condition whr, PageInfo<SysDictEntity> pageInfo, SortField<?>... orderby) {
		SelectSeekStepN<Record> seek = dsl.select().from(DICT).where(whr).orderBy(orderby);
		Result<Record> result = null;
		if (pageInfo != null) {
			SelectForUpdateStep<Record> su = seek.limit(pageInfo.getLimit()).offset(pageInfo.getBeginNum());
			result = su.fetch();
		} else {
			result = seek.fetch();
		}
		if (pageInfo != null) {
			pageInfo.setResult(result);
			pageInfo.setList(result.into(SysDictEntity.class));
		}
		return result;
	}
	public List<SysDictEntity> select(Condition cond, SortField<?>... orderby) {
		Result<Record> result = null;
		if (cond == null) {
			result = this.dsl.select(new SelectField[0]).from(this.DICT).orderBy(orderby).fetch();
		} else {
			result = this.dsl.select(new SelectField[0]).from(this.DICT).where(new Condition[] { cond })
					.orderBy(orderby).fetch();
		}
		return result.into(SysDictEntity.class);
	}

	public Record getById(Integer id) {
		Record record = this.dsl.select(new SelectField[0]).from(DICT)
				.where(new Condition[] { DICT.ID.eq(id) }).fetchOne();
		return record;
	}

	public SysDictEntity getEntityById(Integer id) {
		SysDictEntity entity = null;
		if(id!=null) {
			Record record = dsl.select(new SelectField[0]).from(this.DICT).where(DICT.ID.eq(id)).fetchOne();
			if(record!=null) {
				entity = record.into(SysDictEntity.class);
			}
		}
		return entity;
	}
	public SysDictEntity getEntityById(String id) {
		SysDictEntity entity = null;
		if(id!=null) {
			Record record = dsl.select(new SelectField[0]).from(this.DICT).where(DICT.ID.eq(Integer.valueOf(id))).fetchOne();
			if(record!=null) {
				entity = record.into(SysDictEntity.class);
			}
		}
		return entity;
	}

	public void update(SysDictEntity entity) {
		if (entity.getParentId().equals("")) {
			entity.setParentId(null);
			entity.setTier(1);
		} else {
			Record pRecord = getById(Integer.valueOf(entity.getParentId()));
			entity.setTier(pRecord.get(this.DICT.TIER) + 1);
		}
		SysDictRecord record = new SysDictRecord();
		record.from(entity);
		SysDictEntity p = getEntityById(Integer.valueOf(entity.getParentId()));
		if(p!=null&&p.getCode()!=null) {
			dictCache.invalidate(p.getCode()+","+entity.getCode());
			dictNameCache.invalidate(p.getCode()+","+entity.getName());
		}
		dsl.executeUpdate(record);
	}

	@Transactional
	public String insert(SysDictEntity entity) {
		if (entity.getParentId().equals("")) {
			entity.setParentId(null);
			entity.setTier(Integer.valueOf(1));
		} else {
			Record pRecord = getById( Integer.valueOf(entity.getParentId()) );
			entity.setTier(Integer.valueOf(((Integer) pRecord.get(this.DICT.TIER)).intValue() + 1));
		}
		SysDictRecord record = new SysDictRecord();
		record.from(entity);
		int id = dsl.insertInto(Tables.SYS_DICT).set(record).returning(getTable().ID).fetchOne().getId();
		entity.setId(id + "");
		SysDictEntity p = getEntityById(entity.getParentId());
		if(p!=null) {
			dictCache.invalidate(p.getCode() + "," + entity.getCode());
			dictNameCache.invalidate(p.getCode() + "," + entity.getName());
		}
		return id + "";
	}

	public void deleteById(Integer id) {
		SysDictEntity entity = getEntityById(id);
		SysDictEntity p = getEntityById(entity.getParentId());
		dictCache.invalidate(p.getCode()+","+entity.getCode());
		dictNameCache.invalidate(p.getCode()+","+entity.getName());
		this.dsl.delete(this.DICT).where(new Condition[] { this.DICT.ID.eq(id) }).execute();
	}
	public void deleteById(String id) {
		deleteById(Integer.valueOf(id));
	}
	public static LoadingCache<String, Optional<SysDictEntity>> dictCache = CacheBuilder.newBuilder()
			.maximumSize(5000).build(new CacheLoader<String, Optional<SysDictEntity>>() {
				public Optional<SysDictEntity> load(String key) {
					SysDictService service = BeanAid.getBean(SysDictService.class);
					String[] keys = key.split(",");
					if(keys.length<2) {
						return Optional.fromNullable(null);
					}
					SysDict DICT = SysDict.SYS_DICT.as("DICT");
					List<SysDictEntity> pdicts = service.select(DICT.CODE.eq( keys[0] ));
					if(pdicts.size()==0) {
						return Optional.fromNullable(null);
					}
					SysDictEntity pdict = pdicts.get(0);
					List<SysDictEntity> dicts = service.select(DICT.PARENT_ID.eq(Integer.valueOf(pdict.getId())).and(DICT.CODE.eq( keys[1])));
					if(dicts.size()==0) {
						return Optional.fromNullable(null);
					}
					return Optional.fromNullable(dicts.get(0));
				}
			});

	public static SysDictEntity getFromCaches(String key) {
		if (key == null) {
			return null;
		}
		try {
			Optional<SysDictEntity> dict = dictCache.get(key);
			if(dict==null) {
				return null;
			}
			return dictCache.get(key).orNull();
		} catch (ExecutionException e) {
			e.printStackTrace();
		}
		return null;
	}
	public static LoadingCache<String, Optional<SysDictEntity>> dictNameCache = CacheBuilder.newBuilder()
			.maximumSize(5000).build(new CacheLoader<String, Optional<SysDictEntity>>() {
				public Optional<SysDictEntity> load(String key) {
					SysDictService service = BeanAid.getBean(SysDictService.class);
					String[] keys = key.split(",");
					if(keys.length<2) {
						return Optional.fromNullable(null);
					}
					SysDict DICT = SysDict.SYS_DICT.as("DICT");
					List<SysDictEntity> pdicts = service.select(DICT.CODE.eq( keys[0] ));
					if(pdicts.size()==0) {
						return Optional.fromNullable(null);
					}
					SysDictEntity pdict = pdicts.get(0);
					List<SysDictEntity> dicts = service.select(DICT.PARENT_ID.eq( Integer.valueOf(pdict.getId())).and(DICT.NAME.eq(keys[1])));
					if(dicts.size()==0) {
						return Optional.fromNullable(null);
					}
					return Optional.fromNullable(dicts.get(0));
				}
			});
	
	public static SysDictEntity getFromNameCaches(String key) {
		if (key == null) {
			return null;
		}
		try {
			Optional<SysDictEntity> dict = dictNameCache.get(key);
			if(dict==null) {
				return null;
			}
			return dictNameCache.get(key).orNull();
		} catch (ExecutionException e) {
			e.printStackTrace();
		}
		return null;
	}


	public PageInfo<SysDictEntity> selectByParentId(SysDictEntity sysDictEntity, PageInfo<SysDictEntity> page,SortField<?>... orderby) {
		Long count = countByParentId(sysDictEntity);
		page.setCount(count);
		Result<Record> result = null;
		Condition cond=this.DICT.ID.isNotNull();
		if(StringUtils.isNotBlank(sysDictEntity.getName())){
			cond = cond.and(this.DICT.NAME.like("%"+sysDictEntity.getName()+"%"));
		}
		if(sysDictEntity.getCode()!=null){
			cond = cond.and(this.DICT.CODE.like("%"+sysDictEntity.getCode()+"%"));
		}
		if (sysDictEntity.getParentId() == null) {
			cond = cond.and(this.DICT.PARENT_ID.isNull());
		} else {
			cond = cond.and(this.DICT.PARENT_ID.eq(Integer.valueOf(sysDictEntity.getParentId())));

		}
		System.out.println(cond);
		result = this.dsl.select(new SelectField[0]).from(this.DICT)
				.where(cond).orderBy(orderby)
				.limit(page.getLimit().intValue()).offset(page.getBeginNum()).fetch();
		List<SysDictEntity> list = result.into(SysDictEntity.class);
		page.setResult(result);
		page.setList(list);
		return page;
	}

	public Long countByParentId(SysDictEntity sysDictEntity) {
		Long count = null;
		Condition cond=this.DICT.ID.isNotNull();
		if(StringUtils.isNotBlank(sysDictEntity.getName())){
			cond = cond.and(this.DICT.NAME.like("%"+sysDictEntity.getName()+"%"));
		}
		if(sysDictEntity.getCode()!=null){
			cond = cond.and(this.DICT.CODE.like("%"+sysDictEntity.getCode()+"%"));
		}
		if (sysDictEntity.getParentId() == null) {
			cond = cond.and(this.DICT.PARENT_ID.isNull());
		} else {
			cond = cond.and(this.DICT.PARENT_ID.eq(Integer.valueOf(sysDictEntity.getParentId())));
		}

		count = (Long) this.dsl.selectCount().from(this.DICT)
				.where(cond).fetchOneInto(Long.class);
		return count;
	}
}
